﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Framework.Exceptions.ServiceExceptions;
using Framework.Validation;
using Interfaces.BusinessLogic;
using Interfaces.Models;
using Interfaces.Validation;
using ServiceInfrastructure.Models.SecurityModels;
using ServiceInfrastructure.Models.SecurityModels.Models;
using ServiceInfrastructure.ServiceConstants;

namespace EconomicInformationServiceWcf
{
    public class SecurityService : ISecurityService
    {
        private const string ValidationExcMessage = "Validation error in Register method";
        private const string InvalidRequestExcMessage = "Request contains inconsistent values";
        
        private readonly IInternalSecurityService _securityService;
        private readonly IUserOperationService _userOperationService;
        private readonly IRoleOperationService _roleOperationService;
        private readonly IEntityMapper<IUser, User> _userMapper;
        private readonly IEntityMapper<IRole, Role> _roleMapper; 

        public SecurityService(IInternalSecurityService securityService, 
            IUserOperationService userOperationService, 
            IRoleOperationService roleOperationService, 
            IEntityMapper<IUser, User> userMapper, 
            IEntityMapper<IRole, Role> roleMapper)
        {
            _securityService = securityService;
            _userOperationService = userOperationService;
            _roleOperationService = roleOperationService;
            _userMapper = userMapper;
            _roleMapper = roleMapper;
        }

        public void Login(LoginRequest request)
        {
            var ticket = _securityService.GetTiket(request.Login, request.Password, request.Email);

            var header = new EISSession { Ticket = ticket };

            var response = MessageHeader.CreateHeader(ServiceConstants.Headername,
                                                           ServiceConstants.SecurityServicenamespace, header);

            OperationContext.Current.OutgoingMessageHeaders.Add(response);
        }

        public void Logout()
        {
            var headers = OperationContext.Current.IncomingMessageHeaders;
            var index = headers.FindHeader(ServiceConstants.Headername,
                                           ServiceConstants.SecurityServicenamespace);
            if (index > -1)
            {
                var session = headers.GetHeader<EISSession>(index);
                if (session != null)
                {
                    var userSession = _securityService.DeserializeTiket(session.Ticket);
                    if (userSession != null)
                        _securityService.DisableSession(userSession);
                }
                headers.RemoveAt(index);
            }

        }

        public void Register(RegisterRequest request)
        {
            IValidationResult validationResult = _userOperationService.Validate(request.UserName, request.Password, request.Email, request.Roles, RulesetNames.Create);

            if (validationResult.IsValid)
                _userOperationService.CreateUser(request.UserName, request.Password, request.Email, request.Roles);
            else
                throw new ValidationException(ValidationExcMessage, validationResult);
        }

        public void AddRole(RoleOperationRequest operationRequest)
        {
            _userOperationService.AddRole(operationRequest.Id, operationRequest.Type);
        }

        public void RemoveRole(RoleOperationRequest operationRequest)
        {
            _userOperationService.RemoveRole(operationRequest.Id, operationRequest.Type);
        }

        public void DeleteUser(DeleteUserRequest request)
        {
            _userOperationService.Remove(request.Id);
        }

        public void ChangePassword(ChangePasswordRequest request)
        {
            if(request.NewPassword.Equals(request.ConfirmPassword))
                throw new InvalidMethodRequest(InvalidRequestExcMessage, "New password and confirmation password should be equal");
            
           _userOperationService.UpdatePassword(request.Login, request.Email, request.OldPassword, request.NewPassword);

        }

        public void ResetPassword(ResetPasswordRequest request)
        {
            _userOperationService.ResetPassword(request.UserId);
        }


        public GetUsersResponse GetUsers()
        {
            var users = from user in _userOperationService.GetAllUsers() select _userMapper.Map(user);
            return new GetUsersResponse
                {
                    Users = users
                };
        }

        public GetRolesResponse GetRoles()
        {
            var roles = from role in _roleOperationService.GetAll() select _roleMapper.Map(role);
            return new GetRolesResponse
                {
                    Roles = roles
                };
        }
    }
}
